import json
import functools
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from utils.JWTTool import JwtUtils
import redis
import logging

logger = logging.getLogger(__name__)

# Redis连接
try:
    redis_client = redis.Redis(
        host=getattr(settings, 'REDIS_HOST', 'localhost'),
        port=getattr(settings, 'REDIS_PORT', 6379),
        db=getattr(settings, 'REDIS_DB', 0),
        decode_responses=True
    )
    redis_client.ping()
except:
    redis_client = None

def get_token_from_request(request):
    """从请求中提取JWT token"""
    # Authorization header
    auth_header = request.META.get('HTTP_AUTHORIZATION', '')
    if auth_header.startswith('Bearer '):
        return auth_header[7:]
    
    # Query parameter
    return request.GET.get('token') or request.POST.get('token')

def get_user_from_cache(user_id):
    """从Redis缓存获取用户信息"""
    if not redis_client:
        return None
    try:
        user_data = redis_client.get(f"user:{user_id}")
        return json.loads(user_data) if user_data else None
    except:
        return None

def cache_user_info(user_id, user_data, expire=3600):
    """缓存用户信息到Redis"""
    if not redis_client:
        return
    try:
        redis_client.setex(f"user:{user_id}", expire, json.dumps(user_data))
    except:
        pass

def login_required(view_func):
    """基础登录认证装饰器"""
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if request.method == "OPTIONS":
            return JsonResponse({}, status=200)
            
        token = get_token_from_request(request)
        if not token:
            return JsonResponse({
                "code": 401,
                "msg": "未提供认证令牌",
                "data": None
            }, status=401)
        
        try:
            # 验证JWT token
            payload = JwtUtils.decode_token(token)
            user_id = payload.get('user_id')
            
            if not user_id:
                return JsonResponse({
                    "code": 401,
                    "msg": "无效的认证令牌",
                    "data": None
                }, status=401)
            
            # 从缓存获取用户信息
            user_info = get_user_from_cache(user_id)
            if not user_info:
                # 这里应该从数据库获取用户信息
                user_info = {
                    'id': user_id,
                    'username': payload.get('username', ''),
                    'email': payload.get('email', ''),
                    'roles': payload.get('roles', []),
                    'permissions': payload.get('permissions', [])
                }
                cache_user_info(user_id, user_info)
            
            # 获取真实的User实例
            try:
                from django.contrib.auth import get_user_model
                User = get_user_model()
                user_instance = User.objects.get(id=user_id)
                request.user = user_instance
            except User.DoesNotExist:
                return JsonResponse({
                    "code": 401,
                    "msg": "用户不存在",
                    "data": None
                }, status=401)
            
            # 将用户信息添加到request
            request.user_info = user_info
            request.user_id = user_id
            
            return view_func(request, *args, **kwargs)
            
        except Exception as e:
            logger.error(f"Token验证失败: {str(e)}")
            return JsonResponse({
                "code": 401,
                "msg": "认证令牌验证失败",
                "data": None
            }, status=401)
    
    return wrapper

def permission_required(required_permissions):
    """权限控制装饰器"""
    def decorator(view_func):
        @functools.wraps(view_func)
        @login_required
        def wrapper(request, *args, **kwargs):
            user_permissions = request.user_info.get('permissions', [])
            user_roles = request.user_info.get('roles', [])
            
            # 检查权限
            if isinstance(required_permissions, str):
                permissions_to_check = [required_permissions]
            else:
                permissions_to_check = required_permissions
            
            # 超级管理员直接通过
            if 'admin' in user_roles:
                return view_func(request, *args, **kwargs)
            
            # 检查是否有所需权限
            has_permission = any(perm in user_permissions for perm in permissions_to_check)
            
            if not has_permission:
                return JsonResponse({
                    "code": 403,
                    "msg": "权限不足",
                    "data": None
                }, status=403)
            
            return view_func(request, *args, **kwargs)
        
        return wrapper
    return decorator

def role_required(required_roles):
    """角色控制装饰器"""
    def decorator(view_func):
        @functools.wraps(view_func)
        @login_required
        def wrapper(request, *args, **kwargs):
            user_roles = request.user_info.get('roles', [])
            
            if isinstance(required_roles, str):
                roles_to_check = [required_roles]
            else:
                roles_to_check = required_roles
            
            # 检查是否有所需角色
            has_role = any(role in user_roles for role in roles_to_check)
            
            if not has_role:
                return JsonResponse({
                    "code": 403,
                    "msg": "角色权限不足",
                    "data": None
                }, status=403)
            
            return view_func(request, *args, **kwargs)
        
        return wrapper
    return decorator

def session_required(view_func):
    """会话管理装饰器"""
    @functools.wraps(view_func)
    @login_required
    def wrapper(request, *args, **kwargs):
        user_id = request.user_id
        
        # 检查会话是否有效
        if redis_client:
            try:
                session_key = f"session:{user_id}"
                session_data = redis_client.get(session_key)
                
                if not session_data:
                    return JsonResponse({
                        "code": 401,
                        "msg": "会话已过期",
                        "data": None
                    }, status=401)
                
                # 更新会话过期时间
                redis_client.expire(session_key, 7200)  # 2小时
                
            except Exception as e:
                logger.error(f"会话检查失败: {str(e)}")
        
        return view_func(request, *args, **kwargs)
    
    return wrapper

def oauth_required(provider=None):
    """第三方OAuth认证装饰器"""
    def decorator(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if request.method == "OPTIONS":
                return JsonResponse({}, status=200)
            
            token = get_token_from_request(request)
            if not token:
                return JsonResponse({
                    "code": 401,
                    "msg": "未提供OAuth认证令牌",
                    "data": None
                }, status=401)
            
            try:
                payload = JwtUtils.decode_token(token)
                oauth_provider = payload.get('oauth_provider')
                
                # 检查OAuth提供商
                if provider and oauth_provider != provider:
                    return JsonResponse({
                        "code": 401,
                        "msg": f"需要{provider}认证",
                        "data": None
                    }, status=401)
                
                # 验证OAuth会话
                oauth_user_id = payload.get('oauth_user_id')
                if not oauth_user_id:
                    return JsonResponse({
                        "code": 401,
                        "msg": "无效的OAuth认证",
                        "data": None
                    }, status=401)
                
                request.oauth_info = {
                    'provider': oauth_provider,
                    'oauth_user_id': oauth_user_id,
                    'user_id': payload.get('user_id')
                }
                
                return view_func(request, *args, **kwargs)
                
            except Exception as e:
                logger.error(f"OAuth验证失败: {str(e)}")
                return JsonResponse({
                    "code": 401,
                    "msg": "OAuth认证验证失败",
                    "data": None
                }, status=401)
        
        return wrapper
    return decorator

def api_key_required(view_func):
    """API密钥认证装饰器"""
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        api_key = request.META.get('HTTP_X_API_KEY') or request.GET.get('api_key')
        
        if not api_key:
            return JsonResponse({
                "code": 401,
                "msg": "缺少API密钥",
                "data": None
            }, status=401)
        
        # 验证API密钥
        valid_api_keys = getattr(settings, 'VALID_API_KEYS', [])
        if api_key not in valid_api_keys:
            return JsonResponse({
                "code": 401,
                "msg": "无效的API密钥",
                "data": None
            }, status=401)
        
        return view_func(request, *args, **kwargs)
    
    return wrapper

def rate_limit(max_requests=60, window=60):
    """请求频率限制装饰器"""
    def decorator(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not redis_client:
                return view_func(request, *args, **kwargs)
            
            # 获取客户端IP
            client_ip = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0] or \
                       request.META.get('REMOTE_ADDR', '')
            
            rate_key = f"rate_limit:{client_ip}"
            
            try:
                current_requests = redis_client.get(rate_key)
                if current_requests is None:
                    redis_client.setex(rate_key, window, 1)
                else:
                    current_requests = int(current_requests)
                    if current_requests >= max_requests:
                        return JsonResponse({
                            "code": 429,
                            "msg": "请求过于频繁",
                            "data": None
                        }, status=429)
                    
                    redis_client.incr(rate_key)
                
            except Exception as e:
                logger.error(f"频率限制检查失败: {str(e)}")
            
            return view_func(request, *args, **kwargs)
        
        return wrapper
    return decorator

# 组合装饰器
def secure_api(permissions=None, roles=None, rate_limit_config=None):
    """安全API装饰器组合"""
    def decorator(view_func):
        decorated_func = view_func
        
        # 应用频率限制
        if rate_limit_config:
            decorated_func = rate_limit(**rate_limit_config)(decorated_func)
        
        # 应用权限检查
        if permissions:
            decorated_func = permission_required(permissions)(decorated_func)
        
        # 应用角色检查
        if roles:
            decorated_func = role_required(roles)(decorated_func)
        
        # 应用基础认证
        decorated_func = login_required(decorated_func)
        
        # 添加CSRF豁免
        decorated_func = csrf_exempt(decorated_func)
        
        return decorated_func
    
    return decorator